home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / russell / gc32.lha / finalize.c < prev    next >
C/C++ Source or Header  |  1993-07-29  |  8KB  |  282 lines

  1. /*
  2.  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  3.  * Copyright (c) 1991, 1992 by Xerox Corporation.  All rights reserved.
  4.  
  5.  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  6.  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  7.  *
  8.  * Permission is hereby granted to copy this garbage collector for any purpose,
  9.  * provided the above notices are retained on all copies.
  10.  */
  11. # define I_HIDE_POINTERS
  12. # include "gc.h"
  13. # include "gc_private.h"
  14. # ifdef __STDC__
  15.     typedef void * void_star;
  16. # else
  17.     typedef char * void_star;
  18. # endif
  19.  
  20. # define LOG_TSIZE 7
  21. # define TSIZE (1 << LOG_TSIZE)
  22. # define HASH(addr) \
  23.     ((((word)(addr) >> 3) ^ ((word)(addr) >> (3+LOG_TSIZE))) \
  24.     & (TSIZE - 1))
  25.     
  26. static struct disappearing_link {
  27.     word dl_hidden_obj;        /* Pointer to object base    */
  28.     word dl_hidden_link;    /* Field to be cleared.        */
  29.     struct disappearing_link * dl_next;
  30. } * dl_head[TSIZE] = {0};
  31.  
  32. static struct finalizable_object {
  33.     word fo_hidden_base;    /* Pointer to object base    */
  34.     GC_finalization_proc fo_fn;    /* Finalizer.            */
  35.     ptr_t fo_client_data;
  36.     word fo_object_size;    /* In bytes.            */
  37.     struct finalizable_object * fo_next;
  38. } * fo_head[TSIZE] = {0};
  39.  
  40. # define ALLOC(x, t) t *x = (t *)GC_malloc(sizeof (t))
  41.  
  42. int GC_register_disappearing_link(link)
  43. void_star * link;
  44. {
  45.     ptr_t base;
  46.     
  47.     base = (ptr_t)GC_base((void_star)link);
  48.     if (base == 0)
  49.         ABORT("Bad arg to GC_register_disappearing_link");
  50.     return(GC_general_register_disappearing_link(link, base));
  51. }
  52.  
  53. int GC_general_register_disappearing_link(link, obj)
  54. void_star * link;
  55. void_star obj;
  56. {
  57.     struct disappearing_link *curr_dl;
  58.     int index;
  59.     /* Allocate before acquiring lock */
  60.       ALLOC(new_dl, struct disappearing_link);
  61.     DCL_LOCK_STATE;
  62.     
  63.     index = HASH(link);
  64.     if ((word)link & (ALIGNMENT-1))
  65.         ABORT("Bad arg to GC_general_register_disappearing_link");
  66.     DISABLE_SIGNALS();
  67.     LOCK();
  68.     curr_dl = dl_head[index];
  69.     for (curr_dl = dl_head[index]; curr_dl != 0; curr_dl = curr_dl -> dl_next) {
  70.         if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
  71.             curr_dl -> dl_hidden_obj = HIDE_POINTER(obj);
  72.             UNLOCK();
  73.             ENABLE_SIGNALS();
  74.             GC_free((extern_ptr_t)new_dl);
  75.             return(1);
  76.         }
  77.     }
  78.     {
  79.         new_dl -> dl_hidden_obj = HIDE_POINTER(obj);
  80.         new_dl -> dl_hidden_link = HIDE_POINTER(link);
  81.         new_dl -> dl_next = dl_head[index];
  82.         dl_head[index] = new_dl;
  83.         UNLOCK();
  84.         ENABLE_SIGNALS();
  85.         return(0);
  86.     }
  87. }
  88.  
  89. int GC_unregister_disappearing_link(link)
  90. void_star * link;
  91. {
  92.     struct disappearing_link *curr_dl, *prev_dl;
  93.     int index;
  94.     DCL_LOCK_STATE;
  95.     
  96.     DISABLE_SIGNALS();
  97.     LOCK();
  98.     index = HASH(link);
  99.     if (((unsigned long)link & (ALIGNMENT-1)))
  100.         return(0);
  101.     prev_dl = 0; curr_dl = dl_head[index];
  102.     while (curr_dl != 0) {
  103.         if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
  104.             if (prev_dl == 0) {
  105.                 dl_head[index] = curr_dl -> dl_next;
  106.             } else {
  107.                prev_dl -> dl_next = curr_dl -> dl_next;
  108.             }
  109.             UNLOCK();
  110.             ENABLE_SIGNALS();
  111.             GC_free((extern_ptr_t)curr_dl);
  112.             return(1);
  113.         }
  114.         curr_dl = curr_dl -> dl_next;
  115.         prev_dl = curr_dl;
  116.     }
  117.     UNLOCK();
  118.     ENABLE_SIGNALS();
  119.     return(0);
  120. }
  121.  
  122. void GC_register_finalizer(obj, fn, cd, ofn, ocd)
  123. void_star obj;
  124. GC_finalization_proc fn;
  125. void_star cd;
  126. GC_finalization_proc * ofn;
  127. void_star * ocd;
  128. {
  129.     ptr_t base;
  130.     struct finalizable_object * curr_fo, * prev_fo;
  131.     int index;
  132.     /* Allocate before acquiring lock */
  133.       ALLOC(new_fo, struct finalizable_object);
  134.     DCL_LOCK_STATE;
  135.     
  136.     DISABLE_SIGNALS();
  137.     LOCK();
  138.     base = (ptr_t)GC_base((void_star)obj);
  139.     index = HASH(base);
  140.     if (base != obj)
  141.             ABORT("Bad arg to GC_register_finalizer");
  142.     prev_fo = 0; curr_fo = fo_head[index];
  143.     while (curr_fo != 0) {
  144.         if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
  145.             if (ofn) *ofn = curr_fo -> fo_fn;
  146.             if (ocd) *ocd = (void_star) curr_fo -> fo_client_data;
  147.             if (fn == 0) {
  148.                 /* Delete the structure for base. */
  149.                   if (prev_fo == 0) {
  150.                     fo_head[index] = curr_fo -> fo_next;
  151.                   } else {
  152.                     prev_fo -> fo_next = curr_fo -> fo_next;
  153.                   }
  154.                   UNLOCK();
  155.                   ENABLE_SIGNALS();
  156.                   GC_free((extern_ptr_t)curr_fo);
  157.             } else {
  158.                 curr_fo -> fo_fn = fn;
  159.                 curr_fo -> fo_client_data = (ptr_t)cd;
  160.                 UNLOCK();
  161.                 ENABLE_SIGNALS();
  162.             }
  163.             GC_free((extern_ptr_t)new_fo);
  164.             return;
  165.         }
  166.         curr_fo = curr_fo -> fo_next;
  167.         prev_fo = curr_fo;
  168.     }
  169.     {
  170.         if (ofn) *ofn = 0;
  171.         if (ocd) *ocd = 0;
  172.         if (fn == 0) {
  173.             UNLOCK();
  174.             ENABLE_SIGNALS();
  175.             GC_free((extern_ptr_t)new_fo);
  176.             return;
  177.         }
  178.         new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
  179.         new_fo -> fo_fn = fn;
  180.         new_fo -> fo_client_data = (ptr_t)cd;
  181.         new_fo -> fo_object_size = GC_size(base);
  182.         new_fo -> fo_next = fo_head[index];
  183.         fo_head[index] = new_fo;
  184.     }
  185.     UNLOCK();
  186.     ENABLE_SIGNALS();
  187. }
  188.  
  189. /* Called with world stopped.  Cause disappearing links to disappear,    */
  190. /* and invoke finalizers.                        */
  191. void GC_finalize()
  192. {
  193.     struct disappearing_link * curr_dl, * prev_dl, * next_dl;
  194.     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
  195.     ptr_t real_ptr;
  196.     register int i;
  197.     
  198.   /* Make disappearing links disappear */
  199.     for (i = 0; i < TSIZE; i++) {
  200.       curr_dl = dl_head[i];
  201.       prev_dl = 0;
  202.       while (curr_dl != 0) {
  203.         real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
  204.         if (!GC_is_marked(real_ptr)) {
  205.             *(word *)(REVEAL_POINTER(curr_dl -> dl_hidden_link)) = 0;
  206.             next_dl = curr_dl -> dl_next;
  207.             if (prev_dl == 0) {
  208.                 dl_head[i] = next_dl;
  209.             } else {
  210.                 prev_dl -> dl_next = next_dl;
  211.             }
  212.             GC_clear_mark_bit((ptr_t)curr_dl);
  213.             curr_dl = next_dl;
  214.         } else {
  215.             prev_dl = curr_dl;
  216.             curr_dl = curr_dl -> dl_next;
  217.         }
  218.       }
  219.     }
  220.   /* Mark all objects reachable via chains of 1 or more pointers    */
  221.   /* from finalizable objects.                        */
  222.     for (i = 0; i < TSIZE; i++) {
  223.       for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = curr_fo -> fo_next) {
  224.         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
  225.         if (!GC_is_marked(real_ptr)) {
  226.             GC_push_all(real_ptr, real_ptr + curr_fo -> fo_object_size);
  227.             while (!GC_mark_stack_empty()) GC_mark_from_mark_stack();
  228.         }
  229.         /* 
  230.         if (GC_is_marked(real_ptr)) {
  231.             --> Report finalization cycle here, if desired
  232.         }
  233.         */
  234.       }
  235.     }
  236.   /* Invoke finalization code for all objects that are still        */
  237.   /* unreachable.                            */
  238.     for (i = 0; i < TSIZE; i++) {
  239.       curr_fo = fo_head[i];
  240.       prev_fo = 0;
  241.       while (curr_fo != 0) {
  242.         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
  243.         if (!GC_is_marked(real_ptr)) {
  244.             (*(curr_fo -> fo_fn))(real_ptr, curr_fo -> fo_client_data);
  245.             GC_set_mark_bit(real_ptr);
  246.             next_fo = curr_fo -> fo_next;
  247.             if (prev_fo == 0) {
  248.                 fo_head[i] = next_fo;
  249.             } else {
  250.                 prev_fo -> fo_next = next_fo;
  251.             }
  252.             if (!GC_is_marked((ptr_t)curr_fo)) {
  253.                 ABORT("GC_finalize: found accessible unmarked object\n");
  254.             }
  255.             GC_clear_mark_bit((ptr_t)curr_fo);
  256.             curr_fo = next_fo;
  257.         } else {
  258.             prev_fo = curr_fo;
  259.             curr_fo = curr_fo -> fo_next;
  260.         }
  261.       }
  262.     }
  263. }
  264.  
  265. # ifdef __STDC__
  266.     void_star GC_call_with_alloc_lock(GC_fn_type fn, void_star client_data)
  267. # else
  268.     void_star GC_call_with_alloc_lock(fn, client_data)
  269.     GC_fn_type fn;
  270.     void_star client_data;
  271. # endif
  272. {
  273.     DCL_LOCK_STATE;
  274.     
  275.     DISABLE_SIGNALS();
  276.     LOCK();
  277.     (*fn)(client_data);
  278.     UNLOCK();
  279.     ENABLE_SIGNALS();
  280. }
  281.  
  282.